package com.github.aloxc.plugin.restplus.common;

import com.github.aloxc.plugin.restplus.annotations.SpringRequestParamAnnotations;
import com.github.aloxc.plugin.restplus.component.ServiceNode;
import com.github.aloxc.plugin.restplus.entity.*;
import com.github.aloxc.plugin.restplus.utils.StringUtils;
import com.google.gson.JsonObject;
import com.intellij.notification.*;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
import com.intellij.psi.impl.source.PsiClassReferenceType;
import com.intellij.psi.javadoc.PsiDocComment;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtil;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 请求处理成yapi接口
 */
public class YapiFactory {
    private static NotificationGroup notificationGroup;

    static {
        notificationGroup = new NotificationGroup("Java2Json.NotificationGroup", NotificationDisplayType.BALLOON, true);
    }



    public static YapiDTO build(ServiceNode serviceNode) {
        PsiClass psiClass = serviceNode.getRestServiceItem().getPsiClass();
        PsiMethod psiMethod = serviceNode.getRestServiceItem().getPsiMethod();
        Project project = serviceNode.getRestServiceItem().getModule().getProject();
        // 获得路径
        YapiDTO yapiDTO = new YapiDTO();
        PsiDocComment docComment = psiMethod.getDocComment();
        // 获取类上面是否有swagger的@Api注解 中的value
        String category = null;
        String title = null;
        String requestMethod = serviceNode.getRestServiceItem().getMethod().name();
        PsiAnnotation psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiClass, Consts.Swagger.API);
        if (psiAnnotation != null) {
            PsiNameValuePair[] psiNameValuePairs = psiAnnotation.getParameterList().getAttributes();
            if (psiNameValuePairs.length > 0) {
                for (PsiNameValuePair pair : psiNameValuePairs){
                    if(pair.getName().equals("value")){
                        category = pair.getValue().getText();
                        category = category.substring(1,category.length());
                        category = category.substring(0,category.length()-1);
                    }
                }
            }
        }
        if(category == null){
            category = DesUtil.getDescription(psiClass);
            if (!StringUtils.isNullOrEmpty(category)) {
                category = category.replace("<", "&lt;").replace(">", "&gt;");
            }
        }
        if (category == null) {
            category = com.github.aloxc.plugin.restplus.utils.StringUtils.humpToLine(psiClass.getName());
        }
        yapiDTO.setMenu(category);

        psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiMethod, Consts.Swagger.API_OPERATION);
        String desc = null;
        if (psiAnnotation != null) {
            PsiNameValuePair[] psiNameValuePairs = psiAnnotation.getParameterList().getAttributes();
            if (psiNameValuePairs.length > 0) {
                for (PsiNameValuePair pair : psiNameValuePairs){
                    if(pair.getName().equals("value")){
                        title = pair.getValue().getText();
                        title = title.substring(1,title.length());
                        title = title.substring(0,title.length()-1);
                    }
                    if(pair.getName().equals("notes")){
                        desc = pair.getValue().getText();
                        desc = desc.substring(1,desc.length());
                        desc = desc.substring(0,desc.length()-1);
                    }
                }
            }
        }
        if (title == null) {
            title = com.github.aloxc.plugin.restplus.utils.StringUtils.humpToLine(psiMethod.getName());
        }
        yapiDTO.setTitle(title);


        if(desc == null){
            desc = DesUtil.getDescription(psiMethod);
            if (!StringUtils.isNullOrEmpty(desc)) {
                desc = desc.replace("<", "&lt;").replace(">", "&gt;");
            }
        }
        yapiDTO.setDesc(desc == null ? desc : " <pre><code>  " + desc + "</code> </pre>");
        // 生成响应参数
        yapiDTO.setResponse(YapiFactory.getResponse(project, psiMethod.getReturnType()));
        //生成请求参数
        YapiFactory.getRequest(project, yapiDTO, psiMethod);
        yapiDTO.setPath(serviceNode.getRestServiceItem().getUrl());
        yapiDTO.setMethod(requestMethod);
        // 清空路径
//        if (Objects.nonNull(docComment)) {
//            yapiDTO.setMenu(DesUtil.getMenu(docComment.getText()));
//        }
        return yapiDTO;
    }

    /**
     * @description: 获得请求参数
     * @param: [project, YapiDTO, psiMethodTarget]
     * @return: void
     * @author: chengsheng@qbb6.com
     * @date: 2019/2/19
     */
    public static void getRequest(Project project, YapiDTO YapiDTO, PsiMethod psiMethodTarget) {
        PsiParameter[] psiParameters = psiMethodTarget.getParameterList().getParameters();
        if (psiParameters.length > 0) {
            ArrayList list = new ArrayList<YapiQueryDTO>();
            List<YapiHeaderDTO> yapiHeaderDTOList = new ArrayList<>();
            List<YapiPathVariableDTO> yapiPathVariableDTOList = new ArrayList<>();
            for (PsiParameter psiParameter : psiParameters) {
                if (Consts.JAVA.HTTP_SERVLET_REQUEST.equals(psiParameter.getType().getCanonicalText()) || Consts.JAVA.HTTP_SERVLET_RESPONSE.equals(psiParameter.getType().getCanonicalText())) {
                    continue;
                }
                PsiAnnotation psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiParameter, SpringRequestParamAnnotations.REQUEST_BODY.getQualifiedName());
                if (psiAnnotation != null) {
                    YapiDTO.setRequestBody(getResponse(project, psiParameter.getType()));
                } else {
                    psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiParameter, SpringRequestParamAnnotations.REQUEST_PARAM.getQualifiedName());
                    YapiHeaderDTO yapiHeaderDTO = null;
                    YapiPathVariableDTO yapiPathVariableDTO = null;
                    if (psiAnnotation == null) {
                        psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiParameter, SpringRequestParamAnnotations.REQUEST_ATTRIBUTE.getQualifiedName());
                        if (psiAnnotation == null) {
                            psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiParameter, SpringRequestParamAnnotations.REQUEST_HEADER.getQualifiedName());
                            if (psiAnnotation == null) {
                                psiAnnotation = PsiAnnotationSearchUtil.findAnnotation(psiParameter, SpringRequestParamAnnotations.PATH_VARIABLE.getQualifiedName());
                                yapiPathVariableDTO = new YapiPathVariableDTO();
                            } else {
                                yapiHeaderDTO = new YapiHeaderDTO();
                            }
                        }
                    }
                    if (psiAnnotation != null) {
                        PsiNameValuePair[] psiNameValuePairs = psiAnnotation.getParameterList().getAttributes();
                        YapiQueryDTO yapiQueryDTO = new YapiQueryDTO();

                        if (psiNameValuePairs.length > 0) {
                            for (PsiNameValuePair psiNameValuePair : psiNameValuePairs) {
                                if ("name".equals(psiNameValuePair.getName()) || "value".equals(psiNameValuePair.getName())) {
                                    if (yapiHeaderDTO != null) {
                                        yapiHeaderDTO.setName(psiNameValuePair.getValue().getText().replace("\"", ""));
                                    } else if (yapiPathVariableDTO != null) {
                                        yapiPathVariableDTO.setName(psiNameValuePair.getValue().getText().replace("\"", ""));
                                    } else {
                                        yapiQueryDTO.setName(psiNameValuePair.getValue().getText().replace("\"", ""));
                                    }
                                } else if ("required".equals(psiNameValuePair.getName())) {
                                    yapiQueryDTO.setName(psiParameter.getName());
                                    yapiQueryDTO.setRequired(psiNameValuePair.getValue().getText().replace("\"", "").replace("false", "0").replace("true", "1"));
                                } else if ("defaultValue".equals(psiNameValuePair.getName())) {
                                    if (yapiHeaderDTO != null) {
                                        yapiHeaderDTO.setExample(psiNameValuePair.getValue().getText().replace("\"", ""));
                                    } else {
                                        yapiQueryDTO.setExample(psiNameValuePair.getValue().getText().replace("\"", ""));
                                    }
                                } else {
                                    if (yapiHeaderDTO != null) {
                                        yapiHeaderDTO.setName(StringUtils.isNotBlank(psiNameValuePair.getLiteralValue()) ? psiNameValuePair.getLiteralValue() : psiParameter.getName());
                                        // 通过方法注释获得 描述 加上 类型
                                        yapiHeaderDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                                    }
                                    if (yapiPathVariableDTO != null) {
                                        yapiPathVariableDTO.setName(StringUtils.isNotBlank(psiNameValuePair.getLiteralValue()) ? psiNameValuePair.getLiteralValue() : psiParameter.getName());
                                        // 通过方法注释获得 描述 加上 类型
                                        yapiPathVariableDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                                    } else {
                                        yapiQueryDTO.setName(StringUtils.isNotBlank(psiNameValuePair.getLiteralValue()) ? psiNameValuePair.getLiteralValue() : psiParameter.getName());
                                        // 通过方法注释获得 描述 加上 类型
                                        yapiQueryDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                                    }
                                    if (NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
                                        if (yapiHeaderDTO != null) {
                                            yapiHeaderDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                        } else if (yapiPathVariableDTO != null) {
                                            yapiPathVariableDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                        } else {
                                            yapiQueryDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                        }
                                    } else {
                                        YapiDTO.setRequestBody(getResponse(project, psiParameter.getType()));
                                    }

                                }
                            }
                        } else {
                            if (yapiHeaderDTO != null) {
                                yapiHeaderDTO.setName(psiParameter.getName());
                                // 通过方法注释获得 描述 加上 类型
                                yapiHeaderDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            } else if (yapiPathVariableDTO != null) {
                                yapiPathVariableDTO.setName(psiParameter.getName());
                                // 通过方法注释获得 描述 加上 类型
                                yapiPathVariableDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            } else {
                                yapiQueryDTO.setName(psiParameter.getName());
                                // 通过方法注释获得 描述 加上 类型
                                yapiQueryDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            }
                            if (NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
                                if (yapiHeaderDTO != null) {
                                    yapiHeaderDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                } else if (yapiPathVariableDTO != null) {
                                    yapiPathVariableDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                } else {
                                    yapiQueryDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                                }
                            } else {
                                YapiDTO.setRequestBody(getResponse(project, psiParameter.getType()));
                            }
                        }
                        if (yapiHeaderDTO != null) {
                            if (StringUtils.isNullOrEmpty(yapiHeaderDTO.getDesc())) {
                                // 通过方法注释获得 描述  加上 类型
                                yapiHeaderDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            }
                            if (StringUtils.isNullOrEmpty(yapiHeaderDTO.getExample()) && NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
                                yapiHeaderDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                            }
                            yapiHeaderDTOList.add(yapiHeaderDTO);
                        } else if (yapiPathVariableDTO != null) {
                            if (StringUtils.isNullOrEmpty(yapiPathVariableDTO.getDesc())) {
                                // 通过方法注释获得 描述  加上 类型
                                yapiPathVariableDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            }
                            if (StringUtils.isNullOrEmpty(yapiPathVariableDTO.getExample()) && NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
                                yapiPathVariableDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                            }
                            yapiPathVariableDTOList.add(yapiPathVariableDTO);
                        } else {
                            if (StringUtils.isNullOrEmpty(yapiQueryDTO.getDesc())) {
                                // 通过方法注释获得 描述 加上 类型
                                yapiQueryDTO.setDesc(DesUtil.getParamDesc(psiMethodTarget, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")");
                            }
                            if (StringUtils.isNullOrEmpty(yapiQueryDTO.getExample()) && NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
                                yapiQueryDTO.setExample(NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
                            }
                            list.add(yapiQueryDTO);
                        }
                    } else {
                        // 支持实体对象接收
                        YapiDTO.setReq_body_type("form");
                        if (YapiDTO.getReq_body_form() != null) {
                            YapiDTO.getReq_body_form().addAll(getRequestForm(project, psiParameter, psiMethodTarget));
                        } else {
                            YapiDTO.setReq_body_form(getRequestForm(project, psiParameter, psiMethodTarget));
                        }
                    }
                }
            }
            YapiDTO.setParams(list);
            YapiDTO.setHeader(yapiHeaderDTOList);
            YapiDTO.setReq_params(yapiPathVariableDTOList);
        }
    }

    /**
     * @description: 获得表单提交数据对象
     * @param: [requestClass]
     * @return: java.util.List<java.util.Map < java.lang.String, java.lang.String>>
     */
    public static List<Map<String, String>> getRequestForm(Project project, PsiParameter psiParameter, PsiMethod psiMethod) {
        List<Map<String, String>> requestForm = new ArrayList<>();
        if (NormalTypes.normalTypes.containsKey(psiParameter.getType().getPresentableText())) {
            Map<String, String> map = new HashMap<>();
            map.put("name", psiParameter.getName());
            map.put("type", "text");
            String remark = DesUtil.getParamDesc(psiMethod, psiParameter.getName()) + "(" + psiParameter.getType().getPresentableText() + ")";
            map.put("desc", remark);
            map.put("example", NormalTypes.normalTypes.get(psiParameter.getType().getPresentableText()).toString());
            requestForm.add(map);
        } else {
            PsiClass psiClass = JavaPsiFacade.getInstance(project).findClass(psiParameter.getType().getCanonicalText(), GlobalSearchScope.allScope(project));
            for (PsiField field : psiClass.getAllFields()) {
                if (field.getModifierList().hasModifierProperty("final")) {
                    continue;
                }
                Map<String, String> map = new HashMap<>();
                map.put("name", field.getName());
                map.put("type", "text");
                String remark = DesUtil.getFiledDesc(field.getDocComment());
                remark = DesUtil.getLinkRemark(remark, project, field);
                map.put("desc", remark);
                if (Objects.nonNull(field.getType().getPresentableText())) {
                    Object obj = NormalTypes.normalTypes.get(field.getType().getPresentableText());
                    if (Objects.nonNull(obj)) {
                        map.put("example", NormalTypes.normalTypes.get(field.getType().getPresentableText()).toString());
                    }
                }
                requestForm.add(map);
            }
        }
        return requestForm;
    }

    /**
     * @description: 获得响应参数
     * @param: [project, psiType]
     * @return: java.lang.String
     */
    public static String getResponse(Project project, PsiType psiType) {
        return getPojoJson(project, psiType);
    }


    public static String getPojoJson(Project project, PsiType psiType) {
        if (psiType instanceof PsiPrimitiveType) {
            //如果是基本类型
            KV kvClass = KV.create();
            kvClass.set(psiType.getCanonicalText(), NormalTypes.normalTypes.get(psiType.getPresentableText()));
        } else if (NormalTypes.isNormalType(psiType.getPresentableText())) {
            //如果是包装类型
            KV kvClass = KV.create();
            kvClass.set(psiType.getCanonicalText(), NormalTypes.normalTypes.get(psiType.getPresentableText()));
        } else if (psiType.getPresentableText().startsWith("List")) {
            String[] types = psiType.getCanonicalText().split("<");
            KV listKv = new KV();
            if (types.length > 1) {
                String childPackage = types[1].split(">")[0];
                if (NormalTypes.noramlTypesPackages.keySet().contains(childPackage)) {
                    listKv.set("type", NormalTypes.noramlTypesPackages.get(childPackage));
                } else if (NormalTypes.collectTypesPackages.containsKey(childPackage)) {
                    listKv.set("type", NormalTypes.collectTypesPackages.get(childPackage));
                } else {
                    PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(childPackage, GlobalSearchScope.allScope(project));
                    List<String> requiredList = new ArrayList<>();
                    KV kvObject = getFields(psiClassChild, project, null, null, requiredList);
                    listKv.set("type", "object");
                    listKv.set("properties", kvObject);
                    listKv.set("required", requiredList);
                }
            }
            KV result = new KV();
            result.set("type", "array");
            result.set("title", psiType.getPresentableText());
            result.set("description", psiType.getPresentableText());
            result.set("items", listKv);
            String json = result.toPrettyJson();
            return json;
        } else if (psiType.getPresentableText().startsWith("Set")) {
            String[] types = psiType.getCanonicalText().split("<");
            KV listKv = new KV();
            if (types.length > 1) {
                String childPackage = types[1].split(">")[0];
                if (NormalTypes.noramlTypesPackages.keySet().contains(childPackage)) {
                    listKv.set("type", NormalTypes.noramlTypesPackages.get(childPackage));
                } else if (NormalTypes.collectTypesPackages.containsKey(childPackage)) {
                    listKv.set("type", NormalTypes.collectTypesPackages.get(childPackage));
                } else {
                    PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(childPackage, GlobalSearchScope.allScope(project));
                    List<String> requiredList = new ArrayList<>();
                    KV kvObject = getFields(psiClassChild, project, null, null, requiredList);
                    listKv.set("type", "object");
                    listKv.set("properties", kvObject);
                    listKv.set("required", requiredList);
                }
            }
            KV result = new KV();
            result.set("type", "array");
            result.set("title", psiType.getPresentableText());
            result.set("description", psiType.getPresentableText());
            result.set("items", listKv);
            String json = result.toPrettyJson();
            return json;
        } else if (psiType.getPresentableText().startsWith("Map")) {
            HashMap hashMapChild = new HashMap();
            String[] types = psiType.getCanonicalText().split("<");
            if (types.length > 1) {
                hashMapChild.put("paramMap", psiType.getPresentableText());
            }
            KV kvClass = KV.create();
            kvClass.set(types[0], hashMapChild);
            KV result = new KV();
            result.set("type", "object");
            result.set("title", psiType.getPresentableText());
            result.set("description", psiType.getPresentableText());
            result.set("properties", hashMapChild);
            String json = result.toPrettyJson();
            return json;
        } else if (NormalTypes.collectTypes.containsKey(psiType.getPresentableText())) {
            //如果是集合类型
            KV kvClass = KV.create();
            kvClass.set(psiType.getCanonicalText(), NormalTypes.collectTypes.get(psiType.getPresentableText()));
        } else {
            String[] types = psiType.getCanonicalText().split("<");
            if (types.length > 1) {
                PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(types[0], GlobalSearchScope.allScope(project));
                KV result = new KV();
                List<String> requiredList = new ArrayList<>();
                KV kvObject = getFields(psiClassChild, project, types, 1, requiredList);
                result.set("type", "object");
                result.set("title", psiType.getPresentableText());
                result.set("required", requiredList);

                result.set("description", (psiType.getPresentableText() + " :" + psiClassChild.getName()).trim());
                result.set("properties", kvObject);
                String json = result.toPrettyJson();
                return json;
            } else {
                PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(psiType.getCanonicalText(), GlobalSearchScope.allScope(project));
                KV result = new KV();
                List<String> requiredList = new ArrayList<>();
                KV kvObject = getFields(psiClassChild, project, null, null, requiredList);

                result.set("type", "object");
                result.set("required", requiredList);
                result.set("title", psiType.getPresentableText());
                result.set("description", (psiType.getPresentableText() + " :" + psiClassChild.getName()).trim());
                result.set("properties", kvObject);
                String json = result.toPrettyJson();
                return json;
            }
        }
        return null;
    }

    /**
     * @description: 获得属性列表
     * @param: [psiClass, project, childType, index]
     * @return: com.qbb.build.KV
     * @author: chengsheng@qbb6.com
     * @date: 2019/5/15
     */
    public static KV getFields(PsiClass psiClass, Project project, String[] childType, Integer index, List<String> requiredList) {
        KV kv = KV.create();
        if (psiClass != null) {
            if (Objects.nonNull(psiClass.getSuperClass()) && Objects.nonNull(NormalTypes.collectTypes.get(psiClass.getSuperClass().getName()))) {
                for (PsiField field : psiClass.getFields()) {
                    if (Objects.nonNull(PsiAnnotationSearchUtil.findAnnotation(field, Consts.JAVA.NOT_NULL))) {
                        requiredList.add(field.getName());
                    }
                    getField(field, project, kv, childType, index, psiClass.getName());
                }
            } else {
                if (NormalTypes.genericList.contains(psiClass.getName()) && childType != null && childType.length > index) {
                    String child = childType[index].split(">")[0];
                    PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(child, GlobalSearchScope.allScope(project));
                    return getFields(psiClassChild, project, childType, index + 1, requiredList);
                } else {
                    for (PsiField field : psiClass.getAllFields()) {
                        if (Objects.nonNull(PsiAnnotationSearchUtil.findAnnotation(field, Consts.JAVA.NOT_NULL))) {
                            requiredList.add(field.getName());
                        }
                        getField(field, project, kv, childType, index, psiClass.getName());
                    }
                }
            }
        }
        return kv;
    }

    /**
     * @description: 获得单个属性
     * @param: [field, project, kv, childType, index, pName]
     * @return: void
     */
    public static void getField(PsiField field, Project project, KV kv, String[] childType, Integer index, String pName) {
        if (field.getModifierList().hasModifierProperty("final")) {
            return;
        }
        PsiType type = field.getType();
        String name = field.getName();
        String remark = "";
        if (field.getDocComment() != null) {
            remark = DesUtil.getFiledDesc(field.getDocComment());
            //获得link 备注
            remark = DesUtil.getLinkRemark(remark, project, field);
        }
        // 如果是基本类型
        if (type instanceof PsiPrimitiveType) {
            JsonObject jsonObject = new JsonObject();
            jsonObject.addProperty("type", javaTypeToJsType(type.getPresentableText()));
            if (!StringUtils.isNullOrEmpty(remark)) {
                jsonObject.addProperty("description", remark);
            }
            kv.set(name, jsonObject);
        } else {
            //reference Type
            String fieldTypeName = type.getPresentableText();
            //normal Type
            if (NormalTypes.isNormalType(fieldTypeName)) {
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("type", javaTypeToJsType(fieldTypeName));
                if (!StringUtils.isNullOrEmpty(remark)) {
                    jsonObject.addProperty("description", remark);
                }
                kv.set(name, jsonObject);
            } else if (!(type instanceof PsiArrayType) && ((PsiClassReferenceType) type).resolve().isEnum()) {
                JsonObject jsonObject = new JsonObject();
                jsonObject.addProperty("type", "enum");
                if (!StringUtils.isNullOrEmpty(remark)) {
                    jsonObject.addProperty("description", remark);
                }
                kv.set(name, jsonObject);
            } else if (NormalTypes.genericList.contains(fieldTypeName)) {
                if (childType != null) {
                    String child = childType[index].split(">")[0];
                    if (child.contains("java.util.List") || child.contains("java.util.Set") || child.contains("java.util.HashSet")) {
                        index = index + 1;
                        PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(childType[index].split(">")[0], GlobalSearchScope.allScope(project));
                        getCollect(kv, psiClassChild.getName(), remark, psiClassChild, project, name, pName, childType, index + 1);
                    } else {
                        //class type
                        KV kv1 = new KV();
                        kv1.set(KV.by("type", "object"));
                        PsiClass psiClassChild = JavaPsiFacade.getInstance(project).findClass(child, GlobalSearchScope.allScope(project));
                        kv1.set(KV.by("description", (StringUtils.isNullOrEmpty(remark) ? ("" + psiClassChild.getName().trim()) : remark + " ," + psiClassChild.getName().trim())));
                        if (!pName.equals(psiClassChild.getName())) {
                            List<String> requiredList = new ArrayList<>();
                            kv1.set(KV.by("properties", getFields(psiClassChild, project, childType, index + 1, requiredList)));
                            kv1.set("required", requiredList);
                        } else {
                            kv1.set(KV.by("type", pName));
                        }
                        kv.set(name, kv1);
                    }
                }
                //    getField()
            } else if (type instanceof PsiArrayType) {
                //array type
                PsiType deepType = type.getDeepComponentType();
                KV kvlist = new KV();
                String deepTypeName = deepType.getPresentableText();
                String cType = "";
                if (deepType instanceof PsiPrimitiveType) {
                    kvlist.set("type", javaTypeToJsType(type.getPresentableText()));
                    if (!StringUtils.isNullOrEmpty(remark)) {
                        kvlist.set("description", remark);
                    }
                } else if (NormalTypes.isNormalType(deepTypeName)) {
                    kvlist.set("type", javaTypeToJsType(deepTypeName));
                    if (!StringUtils.isNullOrEmpty(remark)) {
                        kvlist.set("description", remark);
                    }
                } else {
                    kvlist.set(KV.by("type", "object"));
                    PsiClass psiClass = PsiUtil.resolveClassInType(deepType);
                    cType = psiClass.getName();
                    kvlist.set(KV.by("description", (StringUtils.isNullOrEmpty(remark) ? ("" + psiClass.getName().trim()) : remark + " ," + psiClass.getName().trim())));
                    if (!pName.equals(PsiUtil.resolveClassInType(deepType).getName())) {
                        List<String> requiredList = new ArrayList<>();
                        kvlist.set("properties", getFields(psiClass, project, null, null, requiredList));
                        kvlist.set("required", requiredList);
                    } else {
                        kvlist.set(KV.by("type", javaTypeToJsType(pName)));
                    }
                }
                KV kv1 = new KV();
                kv1.set(KV.by("type", "array"));
                kv1.set(KV.by("description", (remark + " :" + cType).trim()));
                kv1.set("items", kvlist);
                kv.set(name, kv1);
            } else if (fieldTypeName.startsWith("List") || fieldTypeName.startsWith("Set") || fieldTypeName.startsWith("HashSet")) {
                //list type
                PsiType iterableType = PsiUtil.extractIterableTypeParameter(type, false);
                PsiClass iterableClass = PsiUtil.resolveClassInClassTypeOnly(iterableType);
                String classTypeName = iterableClass.getName();
                getCollect(kv, classTypeName, remark, iterableClass, project, name, pName, childType, index);
            } else if (fieldTypeName.startsWith("HashMap") || fieldTypeName.startsWith("Map") || fieldTypeName.startsWith("LinkedHashMap")) {
                //HashMap or Map
                CompletableFuture.runAsync(() -> {
                    try {
                        TimeUnit.MILLISECONDS.sleep(700);
                        Notification warning = notificationGroup.createNotification("Map Type Can not Change,So pass", NotificationType.WARNING);
                        Notifications.Bus.notify(warning, project);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
            } else {
                //class type
                KV kv1 = new KV();
                PsiClass psiClass = PsiUtil.resolveClassInType(type);
                kv1.set(KV.by("type", "object"));
                kv1.set(KV.by("description", (StringUtils.isNullOrEmpty(remark) ? ("" + psiClass.getName().trim()) : (remark + " ," + psiClass.getName()).trim())));
                if (!pName.equals(((PsiClassReferenceType) type).getClassName())) {
                    List<String> requiredList = new ArrayList<>();
                    kv1.set(KV.by("properties", getFields(PsiUtil.resolveClassInType(type), project, childType, index, requiredList)));
                    kv1.set("required", requiredList);
                } else {
                    kv1.set(KV.by("type", javaTypeToJsType(pName)));
                }
                kv.set(name, kv1);
            }
        }
    }

    /**
     * Java type to js type string.
     *
     * @param fieldTypeName the field type name
     * @return the string
     */
    public static String javaTypeToJsType(String fieldTypeName) {
        switch (fieldTypeName) {
            case "String":
            case "Character":
            case "char":
                return "string";
            case "Float":
            case "float":
            case "Double":
            case "double":
            case "BigDecimal":
                return "number";
            case "Integer":
            case "int":
            case "long":
            case "Long":
            case "short":
            case "Short":
            case "Byte":
            case "byte":
            case "Date":
                return "integer";
            case "Boolean":
                return "boolean";
            default:
                return fieldTypeName;
        }
    }

    /**
     * 获得集合.
     *
     * @param kv            the kv
     * @param classTypeName the class type name
     * @param remark        the remark
     * @param psiClass      the psi class
     * @param project       the project
     * @param name          the name
     * @param pName         the p name
     * @param childType     the child type
     * @param index         the index
     */
    public static void getCollect(KV kv, String classTypeName, String remark, PsiClass psiClass, Project project, String name, String pName, String[] childType, Integer index) {
        KV<String, Object> kvList = new KV<>();
        if (NormalTypes.isNormalType(classTypeName) || NormalTypes.collectTypes.containsKey(classTypeName)) {
            kvList.set("type", javaTypeToJsType(classTypeName));
            if (!StringUtils.isNullOrEmpty(remark)) {
                kvList.set("description", remark);
            }
        } else {
            kvList.set(KV.by("type", "object"));
            kvList.set(KV.by("description", (StringUtils.isNullOrEmpty(remark) ? ("" + psiClass.getName().trim()) : remark + " ," + psiClass.getName().trim())));
            if (!pName.equals(psiClass.getName())) {
                List<String> requiredList = new ArrayList<>();
                kvList.set("properties", getFields(psiClass, project, childType, index, requiredList));
                kvList.set("required", requiredList);
            } else {
                kvList.set(KV.by("type", pName));
            }
        }
        KV kv1 = new KV();
        kv1.set(KV.by("type", "array"));
        kv1.set(KV.by("description", (StringUtils.isNullOrEmpty(remark) ? ("" + psiClass.getName().trim()) : remark + " ," + psiClass.getName().trim())));
        kv1.set("items", kvList);
        kv.set(name, kv1);
    }
}
